<?php
/**
 * Created by PhpStorm.
 * Author: 黑瞎子
 * Date: 2018/3/17
 * Time: 19:34
 */

namespace app\api\service;


use app\lib\enum\ScopeEnum;
use app\lib\exception\TokenException;
use app\lib\exception\WeChatException;
use think\Exception;
use app\api\model\User as UserModel;

class UserToken extends Token
{
    protected $code;
    protected $wxAppID;
    protected $wxAppSecret;
    protected $wxLoginUrl;

    function __construct($code)
    {
        $this->code = $code;
        $this->wxAppID = config('wx.app_id');
        $this->wxAppSecret = config('wx.app_secret');
        $this->wxLoginUrl = sprintf(config('wx.login_url'),
            $this->wxAppID, $this->wxAppSecret, $this->code);
    }

    public function get(){
        $result = curl_get($this->wxLoginUrl);
        $wxResult = json_decode($result, true);
        if (empty($wxResult)){
            throw new Exception('获取session_key和openID时异常，微信内部错误');
        }else{
            $loginFail = array_key_exists('errcode',$wxResult);
            if ($loginFail){
                $this->processLoginError($wxResult);
            }else{
                return $this->grantToken($wxResult);
            }
        }
    }

    /*
     * 拿到openID
     * 查询数据库，看一下openID是否存在,如果存在则不处理，如果不存在那么新增一条user记录,最终拿到uid
     * 生成令牌，准备缓存数据，写入缓存
     * key:令牌 一个随机字符串
     * value: $wxResult,uid,scope scope用于用户登录区分
     * 把令牌返回客户端
     * */
    private function grantToken($wxResult){
        $openid = $wxResult['openid'];
        $user = UserModel::getOpenID($openid);
        if ($user){
            $uid = $user->id;
        }else{
            $uid = $this->newUser($openid);
        }
        $cacheValue = $this->prepareCacheValue($wxResult,$uid);
        $token = $this->saveToCache($cacheValue);
        return $token;
    }

    //生成令牌，并把用户令牌和信息存入缓存,返回令牌key
    private function saveToCache($cacheValue){
        $key = self::generateToken();
        $value = json_encode($cacheValue);
        $expire_in = config('setting.token_expire_in');

        $request = cache($key, $value, $expire_in);
        if (!$request){
            throw new TokenException([
                'msg' => '服务器缓存异常',
                'code' => 10005
            ]);
        }
        return $key;
    }

    //准备令牌的value值
    private function prepareCacheValue($wxResult, $uid){
        $cacheValue = $wxResult;
        $cacheValue['uid'] = $uid;
        $cacheValue['scope'] = ScopeEnum::User;
        return $cacheValue;
    }

    //添加一条user记录
    private function newUser($openid){
        $user = UserModel::create([
            'openid' => $openid
        ]);
        return $user->id;
    }

    //把微信返回的错误信息赋值到异常
    private function processLoginError($wxResult){
        throw new WeChatException([
            'code' => $wxResult['errcode'],
            'msg' => $wxResult['errmsg']
        ]);
    }
}